//-----------------------------------------------------------------------
// <copyright file="CopyFolder.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation.  All rights reserved.
// THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY 
// KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
// PARTICULAR PURPOSE.
// </copyright>
// <author>Andy Reeves</author>
// <email>andyr</email>
// <date>2004-03-25</date>
// <summary>Copies a folder from one directory to another</summary>
//-----------------------------------------------------------------------

namespace Microsoft.Sdc.Tasks.Folder
{
    using System;
    using System.Xml;
    using System.Globalization;
    using System.IO;
    using System.Collections;

    using Microsoft.Build.Framework;

    /// <summary>
    /// Copies a folder from one directory to another. All files and sub-directories of the source folder will be copied.
    /// </summary>
    /// <remarks>
    /// <code><![CDATA[<Folder.CopyFolder Source="source" Destination="destination" />]]></code>
    /// <para>where:</para>
    /// <para><i>source (Required)</i></para>
    /// <para>
    /// The full path to the source folder that will be copied. This folder must exist.
    /// </para>
    /// <para><i>destination (Required)</i></para>
    /// <para>
    /// The full path to the destination folder that will recieve the copy of Source. This folder will be created if it does not exist.
    /// </para>
    /// </remarks>
    /// <example>
    /// <code><![CDATA[
    /// <Project>
    ///     <Target Name="Test">
    ///         <Folder.CopyFolder
    ///             Source="C:\SourceCopy"
    ///             Destination="C:\DestinationFolder" />
    ///     </Target>
    /// </Project>
    /// ]]></code>    
    /// </example>
    public class CopyFolder : TaskBase
    {
        private string source = String.Empty;
        private string destination = String.Empty;
        
        /// <summary>
        /// The full path to the source directory to be copied. 
        /// </summary>
        /// <value>The full path to the source directory to be copied. This folder must exist or an exception will be thrown.</value>
        [Required]
        public string Source
        {
            get
            {
                return (this.source == null ? String.Empty : this.source);
            }

            set
            {
                this.source = value;
            }
        }

        /// <summary>
        /// The full path to the folder that will recieve the copy of Source.
        /// </summary>
        /// <value>The full path to the folder that will recieve the copy of Source. This folder will be created if it does not exist.</value>
        [Required]
        public string Destination
        {
            get
            {
                return (this.destination == null ? String.Empty : this.destination);
            }

            set
            {
                this.destination = value;
            }
        }

        /// <summary>
        /// Performs the action of this task.
        /// </summary>
        protected override void InternalExecute()
        {
            #region Execute code

            Log.LogMessageFromResources("Folder.CopyFolder", this.source, this.destination);
            this.CopyDirectory(this.source, this.destination);

            #endregion
        }

        /// <summary>
        /// Copies the contents (folders and files) of a source folder to a destination folder.
        /// </summary>
        /// <param name="sourceFolderName">The folder whose files and directories will be copied. This folder must exist.</param>
        /// <param name="destinationFolderName">The folder where the copy will be made. This folder will be created if it does not exist.</param>
        /// <param name="fileTypes">List of file types to be copied</param>
        private void CopyDirectory(string sourceFolderName, string destinationFolderName, IList fileTypes)
        {
            DirectoryInfo sourceFolderInfo = new DirectoryInfo(sourceFolderName);
            DirectoryInfo destinationFolderInfo = new DirectoryInfo(destinationFolderName);

            if (!sourceFolderInfo.Exists)
            {
                throw new TaskException("Folder.MustExistBeforeCopying", sourceFolderName);
            }

            Directory.CreateDirectory(destinationFolderName);

            DirectoryInfo[] subFolders = sourceFolderInfo.GetDirectories();

            foreach (DirectoryInfo subFolder in subFolders)
            {
                Directory.CreateDirectory(System.IO.Path.Combine(destinationFolderName, subFolder.Name));
                this.CopyDirectory(
                    subFolder.FullName,
                    System.IO.Path.Combine(destinationFolderName, subFolder.Name),
                    fileTypes);
            }

            FileInfo[] files = sourceFolderInfo.GetFiles();

            foreach (FileInfo fileEnumerator in files)
            {
                if ((null == fileTypes)
                    || (0 == fileTypes.Count)
                    || (0 == ((string)(fileTypes[0])).Length))
                {
                    fileEnumerator.CopyTo(System.IO.Path.Combine(destinationFolderName, fileEnumerator.Name), true);
                }
                else
                {
                    bool isInterestingFileType = (-1 != fileTypes.IndexOf(
                        fileEnumerator.Extension.ToLower(CultureInfo.InvariantCulture).Trim(new char[] { '*', '.', ' ' })));

                    if (isInterestingFileType)
                    {
                        fileEnumerator.CopyTo(System.IO.Path.Combine(destinationFolderName, fileEnumerator.Name), true);
                    }
                }
            }
        }

        /// <summary>
        /// Copies the contents (folders and files) of a source folder to a destination folder.
        /// </summary>
        /// <param name="sourceFolderName">The folder whose files and directories will be copied. This folder must exist.</param>
        /// <param name="destinationFolderName">The folder where the copy will be made. This folder will be created if it does not exist.</param>
        private void CopyDirectory(string sourceFolderName, string destinationFolderName)
        {
            this.CopyDirectory(sourceFolderName, destinationFolderName, String.Empty);
        }

        /// <summary>
        /// Copies the contents (folders and files) of a source folder to a destination folder.
        /// </summary>
        /// <param name="sourceFolderName">The folder whose files and directories will be copied. This folder must exist.</param>
        /// <param name="destinationFolderName">The folder where the copy will be made. This folder will be created if it does not exist.</param>
        /// <param name="fileSearchPattern">The search pattern specifying the files to copy, for example "*.txt".</param>
        private void CopyDirectory(string sourceFolderName, string destinationFolderName, string fileSearchPattern)
        {
            string[] files = fileSearchPattern.ToLower(CultureInfo.InvariantCulture).Split(';');
            this.CopyDirectory(sourceFolderName, destinationFolderName, files);
        }      
    }
}